import random

from django.contrib.auth.models import Group
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework import status
from user.models import User, Clazz, PersonGroup
from user.serializers import UserSerializer, ClazzSerializer, GroupSerializer
from datetime import datetime
from django_redis import get_redis_connection
from redis import Redis
from django.core.mail import EmailMessage
from django.db.models import Count, Subquery, OuterRef, Exists
from task_manage_sys.serializers import MyTokenObtainPairSerializer
from django.db.models.functions import Concat, NullIf


class UserView(CreateModelMixin, GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        # 判断 账号是否已被注册
        queryset = self.get_queryset().filter(username=request.data['username'])

        if queryset:
            # 提示账号已被注册
            return Response(data={"message": "该账号已被注册"}, status=status.HTTP_404_NOT_FOUND)

        return super().create(request, *args, **kwargs)

    @action(methods=["GET"], detail=False, url_path="code-email", name="code-email")
    def get_code_by_email(self, request, *args, **kwargs):
        # 获取传入的邮箱
        email = request.query_params.get('email')

        if email is None:
            return Response(data={"message": "邮箱不允许为空"}, status=status.HTTP_400_BAD_REQUEST)

        # 查询数据库该账号是否存在
        queryset = self.get_queryset().filter(username=email, is_staff=False)

        if not queryset:
            return Response(data={"message": "该邮箱找不到"}, status=status.HTTP_400_BAD_REQUEST)

        # 生成验证码、并发送邮件
        code = "".join(random.choices("0123456789", k=6))
        redis_client: Redis = get_redis_connection()
        # 将验证码存储到 redis 中
        redis_client.setex(f"email:code:{email}", 10 * 60, code)

        user = queryset[0]

        text = f"""
            <p>尊敬的<b>{user.first_name}{user.last_name}:</b></p>
            <p>您的验证码是<b style='font-size: 30px; color: #f00;'>{code}</b>,请即使使用该验证码，验证码会在10分钟后过期</p>  
            <p>如非本人操作、请忽略该操作即可！</p>   
        """

        message = EmailMessage("任务管理系统-找回密码", body=text, to=(email,))
        # 将内容以 网页形式进行发送
        message.content_subtype = "html"
        # 发送验证码邮件
        message.send()

        return Response(status=status.HTTP_200_OK)


class ClazzView(GenericViewSet):
    queryset = Clazz.objects.all()
    serializer_class = ClazzSerializer

    permission_classes = [AllowAny]

    @action(methods=['GET'], detail=False, url_path="can-user-list", name="can-use-list")
    def can_use_clazz(self, request, *args, **kwargs):
        # 查询 没有毕业的班级 、没有删除的班级
        queryset = self.get_queryset().filter(is_delete=False, state=False)
        # 序列化满足条件的数据
        serializer = self.get_serializer(queryset, many=True, fields=["id", "name", "duration", "manage_name"])
        return Response(data=serializer.data, status=status.HTTP_200_OK)


class ClassViewSet(ModelViewSet):
    queryset = Clazz.objects.all()
    serializer_class = ClazzSerializer

    pagination_class = PageNumberPagination
    PageNumberPagination.page_size_query_param = "rows"

    def list(self, request, *args, **kwargs):
        # 查询 所有没有被删除的班级信息
        queryset = self.get_queryset().filter(is_delete=False).order_by('state', '-start_time')

        # 进行分页
        paginate = self.paginate_queryset(queryset)

        if paginate is None:
            return Response(data={"message": "该请求必须进行分页操作"}, status=status.HTTP_400_BAD_REQUEST)

        # 对 分页后的结果进行序列化
        serializer = self.get_serializer(paginate, many=True)
        # 返回分页后的结果
        return self.get_paginated_response(serializer.data)

    def create(self, request, *args, **kwargs):

        # 查询班级名 是否已添加
        queryset = self.get_queryset().filter(name=request.data['name'], is_delete=False)

        if queryset:
            return Response(data={"message": "班级名已存在"}, status=status.HTTP_400_BAD_REQUEST)

        return super().create(request, *args, **kwargs)

    @action(methods=["DELETE"], detail=False, url_path="batch-remove", name="batch-remove")
    def batch_remove(self, request, *args, **kwargs):
        # 逻辑(软)删除
        self.get_queryset().filter(pk__in=request.data).update(delete_time=datetime.now(), is_delete=True)

        return Response(status=status.HTTP_204_NO_CONTENT)

    def update(self, request, *args, **kwargs):
        # 查询班级是否存在
        queryset = self.get_queryset().filter(name=request.data['name'], is_delete=False)

        if queryset and str(queryset[0].pk) != kwargs[self.lookup_field]:
            return Response(data={"message": "班级名已存在"}, status=status.HTTP_400_BAD_REQUEST)

        # 部分字段进行更新
        kwargs["partial"] = True
        request.data["update_time"] = datetime.now()
        return super().update(request, *args, **kwargs)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance is not None:
            instance.is_delete = True
            instance.delete_time = datetime.now()
            instance.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=["PUT"], detail=True, url_path="graduate", name="graduate")
    def graduate(self, request, *args, **kwargs):

        self.get_queryset().filter(pk=kwargs[self.lookup_field], is_delete=False).update(state=True)

        return Response(status=status.HTTP_200_OK)

    @action(methods=["PUT"], detail=True, url_path="switch", name="switch")
    def switch_clazz(self, request, *args, **kwargs):
        # 查询当前用户、并修改班级信息
        clazz = self.get_object()
        # 修改当前用户的班级关联信息
        User.objects.filter(pk=request.user.pk).update(clazz=clazz)
        # 返回令牌信息
        refresh = MyTokenObtainPairSerializer.get_token(User.objects.get(pk=request.user.pk))

        token = {
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }
        return Response(data=token, status=status.HTTP_200_OK)


class GroupViewSet(ModelViewSet):
    queryset = PersonGroup.objects.all()

    serializer_class = GroupSerializer

    def list(self, request, *args, **kwargs):

        # 查询 满足条件的用户， values('groups') 可以根据用户组 ID 分组
        # user_subquery = User.objects.filter(is_staff=False).filter(groups=OuterRef("group__pk")).values("groups")
        queryset = self.get_queryset().select_related("group").filter(is_delete=False,
                                                                      clazz=request.user.clazz).annotate(
            # 子查询负责查询该组下用户的个数、使用 user_subquery 子查询
            num=Subquery(User.objects.filter(is_staff=False).filter(
                groups=OuterRef("group__pk")).values("groups").annotate(
                count=Count('pk')).values("count"))
        )

        serializer = self.get_serializer(queryset, many=True, fields=["id", "num", "name", "create_time"])

        return Response(data=serializer.data)

    def create(self, request, *args, **kwargs):
        # 查询班级名 是否已添加
        queryset = self.get_queryset().filter(group__name=request.data['name'], is_delete=False)

        if queryset:
            return Response(data={"message": "人员组已存在"}, status=status.HTTP_400_BAD_REQUEST)

        # 添加数据
        group = Group.objects.create(name=request.data['name'])
        instance = PersonGroup.objects.create(group=group, clazz_id=request.user.clazz)
        serializer = self.get_serializer(instance)
        return Response(data=serializer.data, status=status.HTTP_201_CREATED)

    @action(methods=["DELETE"], detail=False, url_path="batch-remove", name="batch-remove")
    def batch_remove(self, request, *args, **kwargs):
        # 逻辑(软)删除
        self.get_queryset().filter(pk__in=request.data).update(delete_time=datetime.now(), is_delete=True)

        return Response(status=status.HTTP_204_NO_CONTENT)

    def update(self, request, *args, **kwargs):
        # 查询班级是否存在
        queryset = self.get_queryset().filter(group__name=request.data['name'], is_delete=False)

        if queryset and str(queryset[0].pk) != kwargs[self.lookup_field]:
            return Response(data={"message": "人员名已存在"}, status=status.HTTP_400_BAD_REQUEST)

        queryset = PersonGroup.objects.select_related("group").filter(pk=kwargs[self.lookup_field])
        # 部分字段进行更新
        queryset.update(update_time=datetime.now())

        group = queryset[0].group
        group.name = request.data['name']
        group.save()
        return Response(status=status.HTTP_200_OK)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance is not None:
            instance.is_delete = True
            instance.delete_time = datetime.now()
            instance.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=["GET"], detail=True, url_path="user-list", name="user-list")
    def groups_user_list(self, request, *args, **kwargs):
        # 查询指定组中的用户
        group_pk = kwargs[self.lookup_field]

        queryset = User.objects.filter(clazz__pk=request.user.clazz, is_staff=False).values('id').annotate(
            name=Concat("first_name", "last_name"),
            exists=Exists(PersonGroup.objects.filter(group__pk=group_pk, group__user=OuterRef("pk"))))

        return Response(data=queryset, status=status.HTTP_200_OK)

    @action(methods=["PUT"], detail=True, url_path="bind-user", name="bind-user")
    def bind_users(self, request, *args, **kwargs):
        # 解除原来的关系
        person_group = PersonGroup.objects.get(pk=kwargs[self.lookup_field])

        users = person_group.group.user_set.all()

        person_group.group.user_set.remove(*users)
        # 绑定新数据关系
        queryset = User.objects.filter(pk__in=request.data)
        person_group.group.user_set.add(*queryset)
        return Response(status=status.HTTP_200_OK)
